<template>
    <div class="container">
        <div class="grid" ref="grid">
            <div class="row" v-for="x in xMax" :key="x">
                <div
                    v-for="y in yMax" :key="y"
                    class="cell" ref="cells"
                    :data-x="x - 1"
                    :data-y="y - 1"
                    :style="{
                        width: `${ cellSize }px`,
                        height: `${ cellSize }px`
                    }"
                    @pointerup="handleCellClick((x - 1) * xMax + (y - 1))">
                </div>
            </div>
        </div>
    </div>
</template>




<script lang='ts' setup>
    import { onMounted, ref, nextTick } from 'vue';
    // 引入gsap
    import gsap from 'gsap';
    import { Physics2DPlugin } from 'gsap/Physics2DPlugin';

    // 网格配置(11 * 11 格子布局)
    const xMax = 11;
    const yMax = 11;
    const cellSize = 24;
    const pullDistance = 70;

    // DOM引用
    const grid = ref<HTMLDivElement | null>(null);
    const cells = ref<HTMLDivElement[]>([]);

    // 初始化状态
    let clicked = ref<boolean>(false);
    let resetAll = ref<boolean>(false);

    // 添加单元格类型定义
    interface CellWidthProps extends HTMLDivElement {
        centerPosition?: {x: number, y: number };
        pulled?: boolean;
    }

    // 更新单元格位置信息
    const updateCellPosistions = () => {
        cells.value.forEach((cell) => {
            const rect = cell.getBoundingClientRect();
            (cell as CellWidthProps).centerPosition = {
                x: (rect.left + rect.right) / 2,
                y: (rect.top + rect.bottom) / 2
            }
        })
    }

    // 处理单元格点击事件
    const handleCellClick = (index: number) => {
        if(clicked.value) return;

        clicked.value = true;

        gsap.to(cells.value, {
            duration: 1.6,
            physics2D: {
                velocity: 'random(400, 1000)',
                angle: 'random(250, 290)',
                gravity: 2000
            },
            stagger: {
                grid: [xMax, yMax],
                from: index,
                amount: .3
            },
            onComplete: function() {
                this.timeScale(-1.3);
            },
            onReverseComplete: () => {
                clicked.value = false;
                resetAll.value = true;
                handlePointerMove();
            }
        });
    }

    // 处理指针移动事件
    const handlePointerMove = (e?: PointerEvent) => {
        if(clicked.value) return;

        const pointerX = e?.pageX ?? -pullDistance;
        const pointerY = e?.pageY ?? -pullDistance;

        cells.value.forEach((cell) => {
            const CellWidthProps = cell as CellWidthProps;
            if(!CellWidthProps.centerPosition) return;

            const diffX = pointerX - CellWidthProps.centerPosition.x;
            const diffY = pointerY - CellWidthProps.centerPosition.y;
            const distance = Math.sqrt(diffX * diffX + diffY * diffY);

            if(distance < pullDistance) {
                const percent = distance / pullDistance;
                CellWidthProps.pulled = true;
                gsap.to(cell, {
                    duration: .2,
                    x: diffX * percent,
                    y: diffY * percent
                });
            }
            else if(CellWidthProps.pulled) {
                CellWidthProps.pulled = false;
                gsap.to(cell, {
                    duration: 1,
                    x: 0,
                    y: 0,
                    ease: 'elastic.out(1, .3)',
                });
            }
        });
        if(resetAll.value) {
            resetAll.value = false;
            gsap.to(cells.value, {
                duration: 1,
                x: 0,
                y: 0,
                ease: 'elastic.out(1, .3)',
            });
        }
    }

    // 初始化
    onMounted(() => {
        gsap.registerPlugin(Physics2DPlugin);

        // 确保DOM完全渲染
        nextTick(() => {
            updateCellPosistions();

            // 事件监听
            window.addEventListener('resize', updateCellPosistions);
            window.addEventListener('pointermove', handlePointerMove);
            document.body.addEventListener('pointerleave', () => handlePointerMove());
        });
    });
</script>



<style lang='less' scoped>
    .container {
        display: grid;
        justify-content: center;
        align-items: center;
        background-color: #0e100f;
        height: 100vh;
        margin: 0;
        overflow: hidden;
        user-select: none;
    }

    .grid {
        --gap: 12px;
        display: flex;
        flex-direction: column;
        gap: var(--gap);
    }

    .row {
        display: flex;
        gap: var(--gap);
    }

    .cell {
        background-color: #fffce1;
        border-radius: 50%;
        will-change: transform;
        cursor: pointer;
    }
</style>    